# -*- coding: utf-8 -*-
# 作者： 安智军
# @Time：2022/7/9 17:12
# @Email：1010666711@qq.com
# @File： 3、闭包.py


'''
闭包也是一个函数
需求：不运行函数 检测任意函数的参数
'''

# 记录任何函数执行的日志
import logging


def f1(a, b):
    print("hello")


def f2(a, b):
    pass


# 使用闭包实现
def logger(func):
    def log_func(*args):
        logging.basicConfig(filename="demo.log", level=logging.INFO)
        logging.info(f"{func.__name__} is running ,arguments is {args}")
        # func(*args) # 可执行f1的hello

    # 返回log_func 不加括号 这就是闭包
    return log_func  # 把函数中的函数给返回了 把函数的引用 传给logger的调用者


f1_logger = logger(f1)
f2_logger = logger(f2)

f1_logger(1, 2)
f2_logger(3, 4)

logger(f1)(5, 6)


# 装饰器的前提是闭包
# 手动实现闭包

def outer_function(n):
    num = n

    def inner_function():
        # nolocal
        nonlocal num  # global (全局) local（局部） nolocal（不是全局不是局部是？不在本局部但是不在全局） num在其他局部 在outer的局部
        num -= 1
        print(num)

    return inner_function  # 返回函数不带括号 为闭包


# 一般情况 函数结束 函数里面的所有的局部变量都会被销毁
# 问： 函数调用结束后 我怎么才能获取到函数里面的局部变量？
# 答：使用闭包（在函数里面在定义一个函数 把局部变量暴露给外部）
my_func = outer_function(3)

my_func()


# python 的入参是传的值还是引用

def add(a, b):
    print(id(a))
    print(id(b))
    return a + b


a = 1
b = 2
print(id(a))
print(id(b))
add(a, b)

''''
140728069222656
140728069222688
140728069222656
140728069222688

传的是引用 使用id（） 查看地址  发现是引用 就像快捷方式
'''


# 写一个方法，实现记录某个函数被调用的次数

def outer():
    c = 0  # 外层函数 不会被销毁 用来记录inner被调用的次数

    def inner():
        nonlocal c
        c += 1
        print(c)

    return inner


count = outer()
count()  # 1
count()  # 2
count()  # 3
